package nl.dxn.tunnel.server.handel;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import nl.dxn.tunnel.enums.ProxyTypeEnum;
import nl.dxn.tunnel.enums.TransferMessageType;
import nl.dxn.tunnel.po.MessageConfig;
import nl.dxn.tunnel.po.TransferMessage;
import nl.dxn.tunnel.server.Constants;
import nl.dxn.tunnel.server.cache.AgentChannelDto;
import nl.dxn.tunnel.server.cache.AgentChannelManager;
import nl.dxn.tunnel.server.cache.AgentServerDto;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;

/**
 * 处理服务器接收到的外部请求
 */
public class ProxyAgentHandler extends SimpleChannelInboundHandler<TransferMessage> {
    private static final Logger logger = LoggerFactory.getLogger(ProxyAgentHandler.class);

    private final HashMap<String, String> agentKeyMap;

    public ProxyAgentHandler(HashMap<String, String> agentKeyMap) {
        this.agentKeyMap = agentKeyMap;
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        super.channelWritabilityChanged(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        ctx.fireUserEventTriggered(evt);
    }

    /**
     * 连接初始化，建立连接
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
    }

    /**
     * 连接中断
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        try {
            logger.info("隧道连接中断");
            AgentChannelManager.disconnectAgentChannel(ctx.channel());
            ctx.fireChannelInactive();
        } catch (Exception ex) {
            logger.error("", ex);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TransferMessage message)  {
        try {
            if (message.getType() == TransferMessageType.TYPE_REGISTER) {
                dealRegister(ctx, message);
                return;
            } else if (message.getType() == TransferMessageType.TYPE_DISCONNECTED) {
                dealDisConnection(message,ctx.channel());
                return;
            } else if (message.getType() == TransferMessageType.TYPE_CONNECTED) {
                AgentChannelManager.completeFuture(message);
                return;
            }

            String serverId = ctx.channel().attr(Constants.SERVER_ID).get();
            if(StringUtils.isBlank(serverId))
            {
                logger.warn("未注册成功，serverId为空，关闭连接");
                ctx.disconnect();
                return;
            }
            else
            {
                AgentServerDto serverDto = AgentChannelManager.getProxy(serverId);
                if (serverDto == null) {
                    logger.warn("未注册成功，serverDto为空，关闭连接");
                    ctx.disconnect();
                    return;
                }
                AgentChannelDto channelDto = serverDto.getChannelById(ctx.channel().id().asLongText());
                if (channelDto == null) {
                    logger.warn("未注册成功，未注册到dto，关闭连接");
                    ctx.disconnect();
                    return;
                }
            }

            if (message.getType() == TransferMessageType.TYPE_KEEPALIVE) {
                ctx.writeAndFlush(message);
                return;
            }

            HashMap<String, Channel> clientMap = ctx.channel().attr(Constants.CLIENT_MAP).get();
            if(clientMap == null)
            {
                return;
            }

            Channel clientChannel = clientMap.get(message.getConfig().getChannelId());
            if(clientChannel == null)
            {
                return;
            }

            ByteBuf byteBuf ;
            if(message.getData() == null)
            {
//                if(message.getConfig().getProxyType() == ProxyTypeEnum.HTTP.code)
//                {
//                    logger.info("http代理失败：{} {}",message.getConfig().getServerId(),message.getConfig().getAgentId());
//                    AgentChannelManager.failHttpStatus(clientChannel.pipeline().lastContext(),"远程代理失败："+message.getConfig().getResult());
//                    return;
//                }
                byteBuf = Unpooled.buffer();
            }
            else
            {
                byteBuf = Unpooled.buffer(message.getData().length);
                byteBuf.writeBytes(message.getData());
            }

            ChannelFuture future = clientChannel.writeAndFlush(byteBuf);
//                if(future.isSuccess())
//                {
//                    byteBuf.release();
//                }
        } catch (Exception ex) {
            logger.error("", ex);
        }
    }



    /**
     * 连接异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

    private void dealRegister(ChannelHandlerContext ctx, TransferMessage transferMessage) {

        MessageConfig questDto = transferMessage.getConfig();

        if (StringUtils.isEmpty(questDto.getAgentId())
                || StringUtils.isEmpty(questDto.getAgentKey())) {
            transferMessage.setType(TransferMessageType.TYPE_AUTH);
            transferMessage.getConfig().setResult("appId和clientKey不能为空");
            ctx.writeAndFlush(transferMessage);
            ctx.close();
            return;
        }

        String key = agentKeyMap.get(questDto.getAgentId());

        if (!questDto.getAgentKey().equals(key)) {
            transferMessage.setType(TransferMessageType.TYPE_AUTH);
            transferMessage.getConfig().setResult("appId或clientKey不正确");
            ctx.writeAndFlush(transferMessage);
            ctx.close();
            return;
        }

        AgentServerDto serverDto = AgentChannelManager.getProxy(questDto.getServerId());
        if(serverDto == null)
        {
            transferMessage.setType(TransferMessageType.TYPE_AUTH);
            transferMessage.getConfig().setResult("proxyId未配置");
            ctx.writeAndFlush(transferMessage);
            ctx.close();
            return;
        }

        if(serverDto.getProxyType() != questDto.getProxyType())
        {
            transferMessage.setType(TransferMessageType.TYPE_AUTH);
            transferMessage.getConfig().setResult("代理类型不正确");
            ctx.writeAndFlush(transferMessage);
            ctx.close();
            return;
        }

        if(!serverDto.getServerKey().equals(questDto.getServerKey()))
        {
            transferMessage.setType(TransferMessageType.TYPE_AUTH);
            transferMessage.getConfig().setResult("connectKey不正确");
            ctx.writeAndFlush(transferMessage);
            ctx.close();
            return;
        }

        ctx.channel().attr(Constants.SERVER_ID).set(questDto.getServerId());

        AgentChannelDto dto = new AgentChannelDto();
        dto.setId(ctx.channel().id().asLongText());
        dto.setProxyId(questDto.getServerId());
        dto.setModes(questDto.getMode());
        dto.setChannel(ctx.channel());
        serverDto.addChannel(dto);

        transferMessage.getConfig().setResult(null);
        transferMessage.setType(TransferMessageType.TYPE_AUTH);
        ctx.writeAndFlush(transferMessage);
        logger.info("隧道客户端授权注册成功,客户端{}使用的秘钥:{},地址：{}", dto.getProxyId(), dto.getId()
                , ctx.channel().remoteAddress());
    }

    private void dealDisConnection(TransferMessage transferMessage,Channel channel) {
        try {
            HashMap<String, Channel> clientMap = channel.attr(Constants.CLIENT_MAP).get();
            if(clientMap != null)
            {
                Channel clientChannel = clientMap.get(transferMessage.getConfig().getChannelId());
                if(clientChannel != null)
                {
                    clientChannel.close();
                }
            }
        }
        catch (Exception ex)
        {
            logger.error("",ex);
        }
    }
}
